﻿using System;
using CoreRay;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace CoreRay.Testing
{
    //-----------------------------------------------------------------------------------------
    /// <summary>
    /// Test class for <see cref="Ray"/> struct.
    /// </summary>
    //-----------------------------------------------------------------------------------------
    [TestClass]
    public class RayTest
    {
        //-----------------------------------------------------------------------------------------
        /// <summary>
        /// Test for the <see cref="Ray"/> constructor.
        /// </summary>
        //-----------------------------------------------------------------------------------------
        [TestMethod]
        public void RayConstructorTest()
        {
            Vector3 origin = new Vector3(52.3f, 85.6f, -21.9f);
            Vector3 direction = new Vector3(2.5f, -8.2f, -3.5f);

            Ray target = new Ray(origin, direction);

            Assert.IsTrue(target.Origin == origin && target.Direction == direction && target.MinimumT == float.Epsilon && target.MaximumT == float.PositiveInfinity);
        }


        //-----------------------------------------------------------------------------------------
        /// <summary>
        /// Test for the <see cref="Ray"/> constructor.
        /// </summary>
        //-----------------------------------------------------------------------------------------
        [TestMethod]
        public void RayConstructorAllParametersTest()
        {
            Vector3 origin = new Vector3(52.3f, 85.6f, -21.9f);
            Vector3 direction = new Vector3(2.5f, -8.2f, -3.5f);
            float minimumT = 0.5f;
            float maximumT = 145.0f;

            Ray target = new Ray(origin, direction, minimumT, maximumT);

            Assert.IsTrue(target.Origin == origin && target.Direction == direction && target.MinimumT == minimumT && target.MaximumT == maximumT);
        }


        //-----------------------------------------------------------------------------------------
        /// <summary>
        /// A test for ComputePoint.
        /// </summary>
        //-----------------------------------------------------------------------------------------
        [TestMethod]
        public void ComputePointTest()
        {
            Vector3 origin = new Vector3(52.3f, 85.6f, -21.9f);
            Vector3 direction = new Vector3(2.5f, -8.2f, -3.5f);

            Ray target = new Ray(origin, direction.Normalize());

            float t = 0.5f;
            Vector3 actual = target.ComputePoint(t);
            Vector3 expected = target.Origin + target.Direction * t;
            
            Assert.AreEqual(expected, actual);
        }


        //-----------------------------------------------------------------------------------------
        /// <summary>
        /// A test for ComputePoint with a parametric point t not in allowed ranges.
        /// </summary>
        //-----------------------------------------------------------------------------------------
        [TestMethod]
        [ExpectedException(typeof(ArgumentException))]
        public void ComputePointNotInRangeTest()
        {
            Vector3 origin = new Vector3(52.3f, 85.6f, -21.9f);
            Vector3 direction = new Vector3(2.5f, -8.2f, -3.5f);

            Ray target = new Ray(origin, direction.Normalize(), 0.5f, 145.0f);

            float t = 0.3f;
            target.ComputePoint(t);
        }


        //-----------------------------------------------------------------------------------------
        /// <summary>
        /// A test for Equals.
        /// </summary>
        //-----------------------------------------------------------------------------------------
        [TestMethod]
        public void EqualsTest()
        {
            Ray ray1 = new Ray(new Vector3(52.3f, 85.6f, -21.9f), new Vector3(2.5f, -8.2f, -3.5f).Normalize());
            Ray ray2 = new Ray(new Vector3(52.3f, 85.6f, -21.9f), new Vector3(2.5f, -8.2f, -3.5f).Normalize());

            bool actual = ray1.Equals(ray2);
            bool expected = true;

            Assert.AreEqual(expected, actual);
        }


        //-----------------------------------------------------------------------------------------
        /// <summary>
        /// A test for equality operator.
        /// </summary>
        //-----------------------------------------------------------------------------------------
        [TestMethod]
        public void op_EqualityTest()
        {
            Ray ray1 = new Ray(new Vector3(52.3f, 85.6f, -21.9f), new Vector3(2.5f, -8.2f, -3.5f).Normalize());
            Ray ray2 = new Ray(new Vector3(52.3f, 85.6f, -21.9f), new Vector3(2.5f, -8.2f, -3.5f).Normalize());

            bool actual = ray1 == ray2;
            bool expected = true;

            Assert.AreEqual(expected, actual);
        }


        //-----------------------------------------------------------------------------------------
        /// <summary>
        /// A test for inequality operator.
        /// </summary>
        //-----------------------------------------------------------------------------------------
        [TestMethod]
        public void op_InequalityTest()
        {
            Ray ray1 = new Ray(new Vector3(52.3f, 85.6f, -21.9f), new Vector3(2.5f, -8.2f, -3.5f).Normalize());
            Ray ray2 = new Ray(new Vector3(82.3f, 45.6f, -28.9f), new Vector3(9.5f, -1.2f, -0.5f).Normalize());
            
            bool actual = ray1 != ray2;
            bool expected = true;

            Assert.AreEqual(expected, actual);
        }
    }
}
